package com.xiaopo.flying.puzzle.slant;

import com.xiaopo.flying.puzzle.Line;
import com.xiaopo.flying.puzzle.ext.PointF;

import static com.xiaopo.flying.puzzle.slant.SlantUtils.intersectionOfLines;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;

/**
 * 分为两种斜线，横谢线和竖线线
 * 横斜线-->start为左边的点，end为右边的点
 * 竖斜线-->start为上面的点，end为下面的点
 *
 * @author wupanjie
 */
class SlantLine implements Line {
    CrossoverPointF start;
    CrossoverPointF end;

    // 移动前的点
    private PointF previousStart = new PointF();
    private PointF previousEnd = new PointF();

    public final Direction direction;

    SlantLine attachLineStart;
    SlantLine attachLineEnd;

    Line upperLine;
    Line lowerLine;

    SlantLine(Direction direction) {
        this.direction = direction;
    }

    SlantLine(CrossoverPointF start, CrossoverPointF end, Direction direction) {
        this.start = start;
        this.end = end;
        this.direction = direction;
    }

    public float length() {
        return (float) sqrt(pow(end.getPointX() - start.getPointX(), 2) + pow(end.getPointY() - start.getPointY(), 2));
    }

    @Override
    public PointF startPoint() {
        return start;
    }

    @Override
    public PointF endPoint() {
        return end;
    }

    @Override
    public Line lowerLine() {
        return lowerLine;
    }

    @Override
    public Line upperLine() {
        return upperLine;
    }

    @Override
    public Line attachStartLine() {
        return attachLineStart;
    }

    @Override
    public Line attachEndLine() {
        return attachLineEnd;
    }

    @Override
    public void setLowerLine(Line lowerLine) {
        this.lowerLine = lowerLine;
    }

    @Override
    public void setUpperLine(Line upperLine) {
        this.upperLine = upperLine;
    }

    @Override
    public Direction direction() {
        return direction;
    }

    @Override
    public float slope() {
        return SlantUtils.calculateSlope(this);
    }

    public boolean contains(float x, float y, float extra) {
        return SlantUtils.contains(this, x, y, extra);
    }

    @Override
    public boolean move(float offset, float extra) {
        if (direction == Direction.HORIZONTAL) {
            if (previousStart.getPointY() + offset < lowerLine.maxY() + extra
                || previousStart.getPointY() + offset > upperLine.minY() - extra
                || previousEnd.getPointY() + offset < lowerLine.maxY() + extra
                || previousEnd.getPointY() + offset > upperLine.minY() - extra) {
                return false;
            }

            start.setPointY(previousStart.getPointY() + offset);
            end.setPointY(previousEnd.getPointY() + offset);
        } else {
            if (previousStart.getPointX() + offset < lowerLine.maxX() + extra
                || previousStart.getPointX() + offset > upperLine.minX() - extra
                || previousEnd.getPointX() + offset < lowerLine.maxX() + extra
                || previousEnd.getPointX() + offset > upperLine.minX() - extra) {
                return false;
            }

            start.setPointX(previousStart.getPointX() + offset);
            end.setPointX(previousEnd.getPointX() + offset);
        }

        return true;
    }

    @Override
    public void prepareMove() {
        previousStart.set(start);
        previousEnd.set(end);
    }

    @Override
    public void update(float layoutWidth, float layoutHeight) {
        intersectionOfLines(start, this, attachLineStart);
        intersectionOfLines(end, this, attachLineEnd);
    }

    @Override
    public float minX() {
        return min(start.getPointX(), end.getPointX());
    }

    @Override
    public float maxX() {
        return max(start.getPointX(), end.getPointX());
    }

    @Override
    public float minY() {
        return min(start.getPointY(), end.getPointY());
    }

    @Override
    public float maxY() {
        return max(start.getPointY(), end.getPointY());
    }

    @Override
    public void offset(float x, float y) {
        start.offset(x, y);
        end.offset(x, y);
    }

    @Override
    public String toString() {
        return "start --> " + start.toString() + ",end --> " + end.toString();
    }
}
